Tutorial step 4: adding start and end routines |
Let's say we want to change our processing formula, so that instead of dividing green and blue in half, we divide it by 3 instead. This immediately gets gross. Division is veeeeeeerry slow, and multiplication tricks aren't much faster and lead to all sorts of rounding problems. Instead, we'll use lookup tables. Now, the only question is where to allocate and initialize the tables.
The startProc and endProc functions |
The startProc function is called immediately before processing starts, and endProc after processing ends. These are the ideal routines to allocate and initialize whatever extra work buffers, lookup tables, or dynamic code strings that may be needed. These functions have the usual prototypes:
int startProc(FilterActivation *fa, const FilterFunctions *ff);
int endProc(FilterActivation *fa, const FilterFunctions *ff);
As usual, return zero for success, non-zero for failure. Unlike the module init functions, VirtualDub calls the endProc function for all filters in the processing chain, including those that have not been initialized and the filter that failed. This means you must keep track of elements that were never allocated (*cou NULL gh*), but also means that you need not worry about deallocating anything in startProc on failure; you can simply net stopProc clean up the partial allocations.
For this to work, though, you must have instance data for the filter. This is done with a non-zero inst_data_size field in the FilterDefinition structure. VirtualDub will automatically allocate a memory block of that size and point the fa->filter_data member to it when a filter instance is created, and deallocate it when instances are destroyed. The memory block is also cleared with zeroes on creation. Because VirtualDub automatically handles instance data allocation, if your filter specifies it needs an instance data block the fa->filter_data pointer will always be valid whenever one of the filter functions is called.
![]() |
![]() You must not store pointers to locations in the instance data block. VirtualDub clones and destroys copies of the fa->filter_data structure when handling the Video Filter dialog. Pointers to the instance data block may not be valid after the dialog appears. This means that you should be especially careful with embedding classes directly in your filter structure. However, it is OK for the instance data block to point to other memory blocks. |
Modifying the tutorial filter to use lookup tables |
First step is to create a structure for our instance data. We'll use two 1K lookup tables, one for green and one for blue. With a Pixel32 for each entry, we can save ourselves some post-shifting trouble.
typedef struct MyFilterData {
Pixel32 *grn_tab;
Pixel32 *blu_tab;
} MyFilterData;
Next, update the FilterDefinition structure:
struct FilterDefinition filterDef_tutorial = {
NULL, NULL, NULL, // next, prev, module
"tutorial", // name
"Emphasizes green and de-emphasizes blue in the image.",
// desc
"anyone", // maker
NULL, // private_data
sizeof(MyFilterData), // inst_data_size
NULL, // initProc
NULL, // deinitProc
tutorialRunProc, // runProc
NULL, // paramProc
NULL, // configProc
NULL, // stringProc
tutorialStartProc, // startProc
tutorialEndProc, // endProc
NULL, // script_obj
NULL, // fssProc
};
Now, write the startProc and stopProc routines. These need not be particularly fast, so there's no sense in optimizing them much:
int tutorialStartProc(FilterActivation *fa, const FilterFunctions *ff) {
MyFilterData *mfd = (MyFilterData *)fa->filter_data;
int i;
if (!(mfd->grn_tab = new Pixel32[256 * 2]))
return 1;
mfd->blu_tab = mfd->grn_tab + 256;
for(i=0; i<256; i++) {
mfd->grn_tab[i] = ((0x200 + i) / 3) << 8;
mfd->blu_tab[i] = i / 3;
}
return 0;
}
int tutorialEndProc(FilterActivation *fa, const FilterFunctions *ff) {
MyFilterData *mfd = (MyFilterData *)fa->filter_data;
delete[] mfd->grn_tab;
mfd->grn_tab = NULL;
return 0;
}
Finally, rewrite the runProc routine to use lookup tables:
int tutorialRunProc(const FilterActivation *fa, const FilterFunctions *ff) {
PixDim w, h;
Pixel32 *src, *dst;
src = (Pixel32 *)fa->src.data;
dst = (Pixel32 *)fa->dst.data;
h = fa->src.h;
do {
w = fa->src.w;
do {
Pixel32 old_pixel, new_pixel;
old_pixel = *src++;
new_pixel = (old_pixel & 0xFF0000)
+ grn_tab[(old_pixel>>8) & 0xff]
+ blu_tab[old_pixel & 0xff];
*dst++ = new_pixel;
} while(--w);
src = (Pixel32 *)((char *)src + fa->src.modulo);
dst = (Pixel32 *)((char *)dst + fa->dst.modulo);
} while(--h);
return 0;
}
The operation was completed successfully. Now, compile and test.
back to main page
tutorial[3]: building the DLL and testing the module
tutorial[5]: changing the output frame size
VirtualDub external filter SDK 1.05 | ©1999-2001 Avery Lee <phaeron@virtualdub.org> |